import base64
import json
import pickle

from django import http
from django.shortcuts import render
from django_redis import get_redis_connection
# Create your views here.
from django.views import View

from carts import constants
from goods.models import SKU
from meiduo_mall.utils.response_code import RETCODE


class CartsView(View):
    '''添加购物车'''
    def post(self,request):
        '''接收和校验参数'''
        '''json为请求参数的话，参数都在请求体中，所以先要获取'''
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')
        count = json_dict.get('count')
        selected = json_dict.get('selected',True)#这个不是必传参数,这个ture是防止判断出现报错
        '''校验参数是否齐，要把参数放列表'''
        if not all([sku_id,count]):
            return http.HttpResponseForbidden('缺少必传参数')

        '''校验sku_id是否正确'''
        try:
            SKU.objects.get(id= sku_id)
        except SKU.DoesNotExiest:
            return http.HttpResponseForbidden('sku_id错误')
        '''校验count是否正确'''
        try:
            count = int(count)
        except SKU.DoesNotExiest:
            return http.HttpResponseForbidden('count错误')
        '''判断selected是否正确'''
        if selected:#这行是判断存在
            if not isinstance(selected,bool):
                return http.HttpResponseForbidden('selected错误')
        '''判断是否登陆'''
        user = request.user

        if user.is_authenticated:#已登陆返回True，未登录返回FALSE
            '''如果用户已登陆就操作redis购物车'''
            redis_conn = get_redis_connection('carts')
            pl = redis_conn.pipeline()
            '''用增量的形式保存商品数据'''
            pl.hincrby('carts_%s' % user.id, sku_id, count)
            '''保存商品的勾选状态'''
            if selected:
                pl.sadd('selected_%s' % user.id,sku_id)
            pl.execute()
            '''响应结果'''
            return http.JsonResponse({'code':RETCODE.OK,'errmsg':'添加购物车成功'})
        else:
            '''如果用户没有登录则操作cookie购物车'''
            '''先获取cookie中的购物车数据，并判断是否有数据'''
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                '''将cart_str转化为bytes类型的字符串'''
                cart_str_bytes = cart_str.encode()
                '''将cart_str_bytes转化为bytes类型的字典'''
                cart_dict_bytes = base64.b64decode(cart_str_bytes)
                '''将cart_dict_bytes转化为真正的字典'''
                cart_dict = pickle.loads(cart_dict_bytes)
            else:
                cart_dict = {}
            # {
            #     "sku_id1": {
            #         "count": "1",
            #         "selected": "True"
            #     },
            '''判断要添加的商品在购物车中是否存在'''
            if sku_id in cart_dict:
                '''增量计算'''
                origin_count = cart_dict[sku_id][count]#取出原有的count
                count += origin_count#增量计算
            cart_dict[sku_id] = {
                'count':count,
                'selected':selected,#把值添加到字典里
            }
            '''把新数据写入到cookies中'''
            '''把原始的购物车进行编码'''
            '''1把cart——dict转化成bytes格式的字典'''
            cart_dict_bytes = pickle._dumps(cart_dict)
            '''2把cart_dict_bytes转化为bytes格式的字符串'''
            cart_str_bytes = base64.b64encode(cart_dict_bytes)
            '''3把cart_str_bytes转化成字符串'''
            cookie_cart_str = cart_str_bytes.decode()
            response = http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok'})
            response.set_cookie('carts',cookie_cart_str,max_age=constants.CARTS_COOKIE_EXPIRES)
            '''实现业务'''
            return response

    def get(self,request):
        '''判断用户是否登陆'''
        user = request.user
        if user.is_authenticated:
            '''查询redis数据库'''
            redis_conn = get_redis_connection('carts')
            '''获取redis中的购物车全部数据'''
            redis_carts = redis_conn.hgetall('carts_%s'% user.id)
            '''获取redis中的选中状态'''
            carts_selected = redis_conn.smembers('selected_%s'% user.id)
            '''将redis中的数据构造成跟cookie中的格式一致，方便统一查询'''
            carts_dict={}
            for sku_id,count in redis_carts.items():
                carts_dict[int(sku_id)] = {
                    'selected':sku_id in carts_selected,
                    'count':int(count),
                }
        else:
            '''用户未登录，查询cookies购物车'''
            carts_str = request.COOKIES.get('carts')
            '''如果有数据则将cart_str转成bytes,再将bytes转成base64的bytes,最后将bytes转字典'''
            if carts_str:
                carts_dict = pickle.loads(base64.b64decode(carts_str.encode()))
            else:
                carts_dict ={}
        '''构造购物车渲染数据'''
        '''先获取字典中所有的key'''
        # {
        #     "sku_id1": {
        #         "count": "1",
        #         "selected": "True"
        #     },
        sku_ids = carts_dict.keys()
        '''一次性拿出所有的sku'''
        skus = SKU.objects.filter(id__in=sku_ids)
        cart_sku = []
        for sku in skus:
            cart_sku.append({
                'id':sku.id,
                'name':sku.name,
                'count': carts_dict.get(sku.id).get('count'),
                'selected': str(carts_dict.get(sku.id).get('selected')),  # 将True，转'True'，方便json解析
                'default_image_url':sku.default_image.url,
                'price':str(sku.price), # 从Decimal('10.2')中取出'10.2'，方便json解析
                'amount':str(sku.price * carts_dict.get(sku.id).get('count')),
            })
            '''构造上下文'''
        context = {
            'cart_sku':cart_sku
        }

        return render(request,'cart.html',context)

    def put(self,request):
        '''接受参数'''
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')
        count = json_dict.get('count')
        selected = json_dict.get('selected',True)
        '''校验参数'''
        '''1校验参数是否齐全'''
        if not all([sku_id,count]):
            return http.HttpResponseForbidden('参数有误')
        '''2校验sku_id是否存在'''
        try:
            sku = SKU.objects.get(id = sku_id)
        except SKU.DoesNotExiest:
            return http.HttpResponseNotFound('商品的sku_id不存在')
        '''3校验count是否为数字'''
        try:
            count = int(count)
        except Exception:
            return http.HttpResponseForbidden('count参数有误')
        '''4判断selected是否为bool值'''
        if selected:
            if not isinstance(selected,bool):
                return http.HttpResponseForbidden('selected有误')

        '''判断用户是否登陆'''
        user = request.user
        if user.is_authenticated:
            '''已登陆则操作redis数据库(hesh值操作方式'''
            redis_conn = get_redis_connection('carts')
            pl = redis_conn.pipeline()
            '''由于后端收到的是最终的结果，所以直接覆盖'''
            pl.hset('carts_%s'% user.id,sku_id,count)
            '''修改勾选状态,selected存储在set中'''
            if selected:
                pl.sadd('selected_%s'% user.id,sku_id)#在user.id的用户的skuid的selected打钩
            else:
                pl.srem('selected_%s'% user.id,sku_id)
            pl.execute()
            '''构建响应数据'''
            cart_sku = {
                'id':sku_id,
                'count':count,
                'selected':selected,
                'name':sku.name,
                'price':sku.price,
                'amount':sku.price * count,
                'default_image_url':sku.default_image.url
            }
            '''响应结果'''
            return http.JsonResponse({'code':RETCODE.OK,'errmsg':'修改购物车成功','cart_sku':cart_sku})
        else:
            '''未登录则操作cookie数据库'''
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                '''# 将cart_str转成bytes,再将bytes转成base64的bytes,最后将bytes转字典'''
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))

            else:
                cart_dict = {}
            '''因为是修改，所以直接覆盖'''
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected,
            }
            ''' # 将字典转成bytes,再将bytes转成base64的bytes,最后将bytes转字符串'''
            cookie_cart_str = base64.b64encode(pickle._dumps(cart_dict)).decode()
            '''构造响应对象'''
            cart_sku = {
                'id': sku_id,
                'count': count,
                'selected': selected,
                'name': sku.name,
                'price': sku.price,
                'amount': sku.price * count,
                'default_image_url': sku.default_image.url
            }
            response =  http.JsonResponse({'code':RETCODE.OK,'errmsg':'修改购物车成功','cart_sku':cart_sku})
            '''# 响应结果并将购物车数据写入到cookie'''
            response.set_cookie('carts',cookie_cart_str,max_age=constants.CARTS_COOKIE_EXPIRES)
            return response

    def delete(self,request):
        '''接受和校验参数'''
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')
        '''校验sku_id是否存在'''
        try:
            SKU.objects.get(id = sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseForbidden('参数sku_id不存在')
        '''判断用户是否登陆'''
        user = request.user
        if user.is_authenticated():
            '''用户已登陆，删除redis购物车'''
            redis_conn = get_redis_connection('carts')
            pl = redis_conn.pipeline()
            pl.hdel('carts_%s'% user.id,sku_id)
            pl.srem('selected_%s'% user.id,sku_id)
            pl.execute()
            return http.JsonResponse({'code':RETCODE.OK,'errmsg':'删除购物车成功'})
        else:
            '''用户未登录，操作cookies'''
            cart_str = request.COOKIES.get('carts')
            '''# 将cart_str转成bytes,再将bytes转成base64的bytes,最后将bytes转字典'''
            if cart_str:
                cart_dict =pickle._dumps(base64.b64encode(cart_str.encode()))
            else:
                cart_dict = {}
            response = http.JsonResponse({'code': RETCODE.OK, 'errmsg': '删除购物车成功'})
            if sku_id in cart_dict:
                del cart_dict[sku_id]
                # 将字典转成bytes,再将bytes转成base64的bytes,最后将bytes转字符串
                cart_dict_str = base64.b64encode(pickle._dumps(cart_dict)).decode()
                '''将处理之后的信息设置到cookie中'''
                response.set_cookie('carts',cart_dict_str,max_age=constants.CARTS_COOKIE_EXPIRES)
            return response

class CartsSelectAllView(View):
    def put(self,request):
        '''接受参数'''
        json_dict = json.loads(request.body.decode())
        selected = json_dict.get('selected',True)
        '''校验参数selected是否为bool'''
        if selected:
            if not isinstance(selected,bool):
                return http.HttpResponseForbidden('参数selected有误')
        '''判断用户是否登陆'''
        user = request.user
        if user.is_authenticated():
            '''用户登录操作redis数据库'''
            redis_conn = get_redis_connection('carts')
            '''获取购物车内的所有信息'''
            cart = redis_conn.hgetall('carts_%s'% user.id)
            '''获取所有商品的skuid'''
            sku_id_list = cart.keys()
            '''全选购物车'''
            if selected:
                redis_conn.sadd('selected_%s'% user.id,*sku_id_list)
            else:
                '''取消全选'''
                redis_conn.srem('selected_%s'% user.id,*sku_id_list)
            return http.JsonResponse({'code':RETCODE.OK,'errmsg':'修改购物车成功'})
        else:
            '''用户未登录操作cookies'''
            cart = request.COOKIES.get('carts')
            response = http.JsonResponse({'code':RETCODE.OK,'errmsg':'修改购物车成功'})
            '''如果购物车不为空则，进行操作'''
            if cart is not None:
                cart = pickle.loads(base64.b64decode(cart.encode()))
                for sku_id in cart:
                    cart[sku_id]['selected'] = selected
                cart_dict = base64.b64encode(pickle._dumps(cart)).decode()
                response.set_cookie('carts',cart_dict,max_age=constants.CARTS_COOKIE_EXPIRES)
            return response

class CartsSimpleView(View):
    """商品页面右上角购物车"""

    def get(self, request):
        # 判断用户是否登录
        user = request.user
        if user.is_authenticated:
            # 用户已登录，查询Redis购物车
            redis_conn = get_redis_connection('carts')
            redis_cart = redis_conn.hgetall('carts_%s' % user.id)
            cart_selected = redis_conn.smembers('selected_%s' % user.id)
            # 将redis中的两个数据统一格式，跟cookie中的格式一致，方便统一查询
            cart_dict = {}
            for sku_id, count in redis_cart.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in cart_selected
                }
        else:
            # 用户未登录，查询cookie购物车

            cart_str = request.COOKIES.get('carts')
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}
            # 构造简单购物车JSON数据
        cart_skus = []
        sku_ids = cart_dict.keys()
        skus = SKU.objects.filter(id__in=sku_ids)
        for sku in skus:
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'count': cart_dict.get(sku.id).get('count'),
                'default_image_url': sku.default_image.url
            })

        # 响应json列表数据
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'cart_skus': cart_skus})